/**
 * In the program in Figure 15.18, use the standard I/O library for reading and writing the
 * pipes instead of read and write.
 **/
#include "apue.h"

static void sig_pipe(int); /* our signal handler */

int main(void)
{
  int n, fd1[2], fd2[2];
  pid_t pid;
  char line[MAXLINE];
  FILE *fin, *fout; /*I/O流 */

  if (signal(SIGPIPE, sig_pipe) == SIG_ERR)
    err_sys("signal error");

  if (pipe(fd1) < 0 || pipe(fd2) < 0)
    err_sys("pipe error");

  if ((pid = fork()) < 0) {
    err_sys("fork error");
  } else if (pid > 0) { /* parent */
    close(fd1[0]);
    close(fd2[1]);

    // 输入流
    fin = fdopen(fd2[0], "r");
    if (fin == NULL) {
      err_sys("fdopen error");
    }
    // 设置行缓冲
    if (setvbuf(fin, NULL, _IOLBF, 0) != 0) {
      err_sys("setvbuf error");
    }
    // 输出流
    fout = fdopen(fd1[1], "w");
    if (fout == NULL) {
      err_sys("fdopen error");
    }
    if (setvbuf(fout, NULL, _IOLBF, 0) != 0) {
      err_sys("setvbuf error");
    }

    while (fgets(line, MAXLINE, stdin) != NULL) {
      n = strlen(line);
      if (fputs(line, fout) == EOF) /* 替换write */
        err_sys("write error to pipe");
      if (fgets(line, MAXLINE, fin) == NULL) { /* 替换read */
        err_msg("child closed pipe");
        break;
      }
      n = strlen(line);
      line[n] = 0; /* null terminate */
      if (fputs(line, stdout) == EOF)
        err_sys("fputs error");
    }

    if (ferror(stdin))
      err_sys("fgets error on stdin");
    exit(0);
  } else { /* child */
    close(fd1[1]);
    close(fd2[0]);
    if (fd1[0] != STDIN_FILENO) {
      if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO)
        err_sys("dup2 error to stdin");
      close(fd1[0]);
    }

    if (fd2[1] != STDOUT_FILENO) {
      if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO)
        err_sys("dup2 error to stdout");
      close(fd2[1]);
    }
    if (execl("./add2", "add2", (char *)0) < 0)
      err_sys("execl error");
  }
  exit(0);
}

static void sig_pipe(int signo)
{
  printf("SIGPIPE caught\n");
  exit(1);
}
